package com.platform.modules.ws;

import cn.hutool.core.lang.Dict;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.platform.common.constant.AppConstants;
import com.platform.common.enums.ResultCodeEnum;
import com.platform.common.exception.BaseException;
import com.platform.common.shiro.vo.LoginUser;
import com.platform.modules.auth.service.TokenService;
import com.platform.modules.push.vo.PushResultVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@ServerEndpoint(value = "/ws")
public class BootWebSocketHandler extends TextWebSocketHandler {

    private static final ConcurrentHashMap<Long, List<Session>> POOL_SESSION = new ConcurrentHashMap<>();

//    @Resource
//    private ChatPushService chatPushService;

    private TokenService tokenService = null;

    @OnOpen
    public void onOpen(Session session){
        // log.info("websocket session created, sessionId="+session.getId());
       String queryString =  session.getQueryString();
       log.info("queryString:"+queryString);
       String[] queryArray = queryString.split("&");
       String[] tokenHead = queryArray[0].split("=");
       if(tokenHead.length==1){
           return;
       }
       if("Authorization".equals(tokenHead[0]) && StringUtils.isNotEmpty(tokenHead[1])){
           String token = tokenHead[1];
           if(tokenService==null){
               tokenService = SpringUtil.getBean("tokenService");
           }
           LoginUser loginUser = tokenService.queryByToken(token);
           if(loginUser==null){
               return;
           }else{
               Long userId = loginUser.getUserId();
               session.getUserProperties().put("userId", userId);
               String deviceType = queryArray[1].split("=")[1];
               session.getUserProperties().put("deviceType", deviceType);
               if(POOL_SESSION.get(userId)==null){
                   List<Session> sessionList = new ArrayList<>();
                   sessionList.add(session);
                   POOL_SESSION.put(userId, sessionList);
               }else{
                   // 判断会话列表中是否已包含打开的websocket会话，用户在同一种类型的设备上只能保持一个websocket会话
                   boolean containsFlag = false;
                   for(Session session1: POOL_SESSION.get(userId)){
                       if(deviceType.equals(session1.getUserProperties().get("deviceType"))){
                           containsFlag = true;
                       }
                   }
                   // 不包含则加入会话列表
                   if(!containsFlag){
                       POOL_SESSION.get(userId).add(session);
                   }
               }
           }
       }
    }

    @OnClose
    public void onClose(Session session){
        log.info("websocket session closed, sessionId="+session.getId());
        String queryString =  session.getQueryString();
        log.info("queryString:"+queryString);
        String[] queryArray = queryString.split("&");
        String[] tokenHead = queryArray[0].split("=");
        if(tokenHead.length==1){
            return;
        }
        if("Authorization".equals(tokenHead[0]) && StringUtils.isNotEmpty(tokenHead[1])){
            String token = tokenHead[1];
            String deviceType = queryArray[1].split("=")[1];
            if(tokenService==null){
                tokenService = SpringUtil.getBean("tokenService");
            }
            LoginUser loginUser = tokenService.queryByToken(token);
            Long userId = loginUser.getUserId();
            List<Session> sessionList = POOL_SESSION.get(userId);
            if(sessionList!=null && sessionList.size()>0){
                Iterator<Session> iterator = sessionList.iterator();
                while (iterator.hasNext()){
                    Session session1 = iterator.next();
                    if(deviceType.equals(session1.getUserProperties().get("deviceType"))){
                        iterator.remove();
                    }
                }
            }
        }

    }

    @OnError
    public void onError(Session session, Throwable ex){
        log.error("websocket session error, sessionId="+session.getId(), ex);
    }

    @OnMessage
    public void onMessage(String message, Session session){
      // log.info("received client websocket message: "+message+",sessionId="+session.getId());
    }

    /**
     * socket 建立成功事件
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        Long userId = (Long) session.getAttributes().get(AppConstants.USER_ID);
        if (userId == null) {
            throw new BaseException(ResultCodeEnum.UNAUTHORIZED);
        }
        /**
        List<WebSocketSession> sessionList = POOL_SESSION.get(userId);
        if (CollectionUtils.isEmpty(sessionList)) {
            POOL_SESSION.put(userId, sessionList = new ArrayList<>());
        }
        sessionList.add(session);
        // 拉取离线消息
        chatPushService.pullOffLine(userId);
         */
    }

    /**
     * 接收消息事件
     */
    @SneakyThrows
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) {
        // 获得客户端传来的消息
        String payload = message.getPayload();
        log.info("server 接收到消息 {}", payload);
        session.sendMessage(new TextMessage("ok"));
    }

    /**
     * socket 断开连接时
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        Long userId = (Long) session.getAttributes().get(AppConstants.USER_ID);
        if (userId == null) {
            throw new BaseException(ResultCodeEnum.UNAUTHORIZED);
        }
        /**
        List<WebSocketSession> sessionList = POOL_SESSION.get(userId);
        if (CollectionUtils.isEmpty(sessionList)) {
            return;
        }
        sessionList.remove(session);
         */
    }

    /**
     * 给某个用户发送消息
     */
    public PushResultVo sendMsg(Long userId, Dict transmission) {
        List<Session> sessionList = POOL_SESSION.get(userId);
        if (CollectionUtils.isEmpty(sessionList)) {
            return PushResultVo.fail();
        }
        int result = 0;
        String sendMessage = JSONUtil.toJsonStr(transmission);
        log.info("sendMessage:"+sendMessage);
        for (Session session : sessionList) {
            try {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(sendMessage);
                    result++;
                }
            } catch (IOException e) {
                log.error("发送消息给{}失败", userId, e);
            }
        }
        if (result == 0) {
            return PushResultVo.fail();
        }
        return PushResultVo.success();
    }

}